package com.alibaba.csp.sentinel.dashboard.rule.nacos.cluster;

import com.alibaba.csp.sentinel.dashboard.domain.cluster.ClusterGroupEntity;
import com.alibaba.csp.sentinel.dashboard.domain.cluster.config.ClusterClientConfig;
import com.alibaba.csp.sentinel.dashboard.domain.cluster.request.ClusterAppAssignMap;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;

@Component(value = "clusterMapDataNacosPublisher")
public class ClusterMapDataNacosPublisher implements DynamicRulePublisher<List<ClusterAppAssignMap>> {

    @Autowired
    private ConfigService configService;

    @Override
    public void publish(String app, List<ClusterAppAssignMap> rules) throws Exception {
        if (null == rules) {
            return;
        }
        List<ClusterGroupEntity> groupEntityList = new ArrayList<>(rules.size());
        rules.forEach(clusterAppAssignMap -> {
            ClusterGroupEntity clusterGroupEntity = new ClusterGroupEntity();
            clusterGroupEntity.setMachineId(clusterAppAssignMap.getMachineId());
            clusterGroupEntity.setIp(clusterAppAssignMap.getIp());
            clusterGroupEntity.setPort(clusterAppAssignMap.getPort());
            clusterGroupEntity.setClientSet(clusterAppAssignMap.getClientSet());
            clusterGroupEntity.setMaxAllowedQps(clusterAppAssignMap.getMaxAllowedQps());
            groupEntityList.add(clusterGroupEntity);
            try {
                handle(app, clusterAppAssignMap.getClientSet());
            } catch (NacosException e) {
                throw new RuntimeException(e);
            }
        });
        String name = app + NacosConfigUtil.CLUSTER_MAP_DATA_ID_POSTFIX;
        configService.publishConfig(name, NacosConfigUtil.GROUP_ID, JSON.toJSONString(groupEntityList));
    }

    private void handle(String app, Set<String> clientSet) throws NacosException {
        if (CollectionUtils.isEmpty(clientSet)) {
            return;
        }
        String name = app + NacosConfigUtil.CLIENT_CONFIG_DATA_ID_POSTFIX;
        String data = configService.getConfig(name, NacosConfigUtil.GROUP_ID, 3000);
        if (StringUtil.isBlank(data)) {
            return;
        }
        Map<String, ClusterClientConfig> configMap = JSON.parseObject(data, new TypeReference<Map<String, ClusterClientConfig>>() {
        });
        if (CollectionUtils.isEmpty(configMap)) {
            return;
        }
        Set<String> deleteKey = new HashSet<>();
        configMap.forEach((key, value) -> {
            if (!clientSet.contains(key)) {
                deleteKey.add(key);
            }
        });
        if (CollectionUtils.isEmpty(deleteKey)) {
            return;
        }
        deleteKey.forEach(configMap::remove);
        configService.publishConfig(name, NacosConfigUtil.GROUP_ID, JSON.toJSONString(configMap));
    }
}
